<template>
  <div :class="`icon-editor ${visualThemeClassName}`">
    <Icon
      v-if="hasConf()"
      :conf="rooterIcon"
      class="rooter_icon"
      :style="rooterIconStyle"
      :resize="false"
      preview
      @click="editIcon"
    />
    <Icon
      v-else
      :conf="emptyIcon"
      class="empty_icon"
      :resize="false"
      @click="editIcon"
    />

    <el-dialog
      v-if="dialogVisible"
      v-model="dialogVisible"
      :title="$demoi18n('panel.iconEditor.editIcon')"
      :class="`icon_editor_dialog ${visualThemeClassName} ${xvueNameSpace}`"
      :close-on-click-modal="false"
      :append-to-body="true"
      :destroy-on-close="true"
      width="1030px"
      @close="cancel"
    >
      <div :class="`icons_box for_${componentStyle} ${visualThemeClassName}`">
        <div class="icon_box_tips">{{ $demoi18n('icon-editor.popTip') }}</div>
        <div class="icon_box_conts">
          <IconEditorCategory ref="cates" :mode="mode" @cur-cate-change="setActiveTab" @get-sever-cates="onGetSeverCates" />
          <div class="icons_wrap">
            <div class="icons">
              <div :class="`list for_${curTab.key}`">

                <!-- 前端png图片 -->
                <div v-if="curTab.type === 'png'" class="list_inner">
                  <span
                    v-for="(img, index) in iconsMap[curTab.key].list"
                    :key="index"
                    :class="getClassName(img)"
                    @click="selectIcon(img)"
                  >
                    <Icon
                      :ref="img.icon_id"
                      :conf="getPngIcon(img)"
                      :resize="false"
                    />
                  </span>
                </div>

                <!-- 前端iconfont -->
                <div v-else-if="curTab.type === 'iconfont'" class="list_inner">
                  <span
                    v-for="(img, index) in iconsMap[curTab.key].list"
                    :key="index"
                    :class="getClassName(img)"
                    @click="selectIcon(img)"
                  >
                    <Icon
                      :ref="img.icon_id"
                      :conf="getIconfontIcon(img)"
                      :resize="false"
                    />
                  </span>
                </div>

                <!-- 服务器图片 -->
                <div
                  v-else-if="curTab.type === 'serverImg' || curTab.type === 'serverImgDefault'"
                  class="for_serverImg_inner"
                >
                  <!-- 工具条 -->
                  <div v-if="curTab.type === 'serverImg'" class="topBtns">
                    <div class="actions">
                      <el-button
                        :class="{ batch_rooter: true, on: multiActsAvailable }"
                        :link="true"
                        type="primary"
                        icon="Grid"
                        :title="$demoi18n('word.operation')"
                        @click="toggleActExtends()"
                      ></el-button>
                    </div>
                  </div>

                  <!-- 扩展工具条 -->
                  <div
                    v-show="multiActsAvailable"
                    class="actions_extend"
                  >
                    <el-button
                      v-if="curTab.key !== 'custom'"
                      size="default"
                      :disabled="hasSelected"
                      @click="moveServerImgs()"
                    >{{ $demoi18n('icon-editor.transferCate') }}</el-button>
                    <el-button
                      size="default"
                      :disabled="hasSelected"
                      @click="delSeverImgs(false)"
                    >{{
                      $demoi18n('iconEditor.batchDelete')
                    }}</el-button>
                    <el-button
                      size="default"
                      @click="delSeverImgs(true)"
                    >{{ $demoi18n('word.clear') }}</el-button>
                    <el-button
                      size="default"
                      class="cancel_select_all"
                      @click="toggleActExtends(false)"
                    >{{
                      $demoi18n('panel.confirm.cancel')
                    }}</el-button>
                  </div>

                  <!-- 未分类，自定义图标 -->
                  <div v-if="curTab.key === 'custom'" class="list_inner">
                    <div class="custom_desc">{{ $demoi18n('icon-editor.customCateDesc') }}</div>
                    <IconUploader
                      v-show="!multiActsAvailable"
                      :widget-instance-id="widgetInstanceId"
                      class="it"
                      @upload-complete="uploadComplete"
                    />
                    <span
                      v-for="(img) in iconsMap['custom'].list"
                      :key="img.icon_id"
                      :class="getClassName(img)"
                      @click="selectIcon(img)"
                    >
                      <Icon
                        :ref="img.icon_id"
                        :conf="getServerImgIcon(img, 6)"
                        :resize="false"
                        preview
                        check-exist
                        @img-load-err="serverImgLoadErr(img)"
                      />
                    </span>
                  </div>

                  <!-- 分类下图片 -->
                  <div
                    v-else-if="curTab.type === 'serverImg' || curTab.type === 'serverImgDefault'"
                    ref="cateImgs"
                    :class="`list_inner tab_${curTab.key}`"
                    @scroll="scrollGetCateImgs()"
                  >
                    <IconUploader
                      v-show="!multiActsAvailable && curTab.type === 'serverImg' && curTab.count<100"
                      :widget-instance-id="widgetInstanceId"
                      class="it"
                      :cateId="curTab.key"
                      @upload-complete="uploadComplete"
                    />
                    <span
                      v-for="(img) in cateIconList"
                      :key="img.icon_id"
                      :class="getClassName(img)"
                      @click="selectIcon(img)"
                    >
                      <Icon
                        :ref="img.icon_id"
                        :conf="getServerImgIcon(img, 9, true)"
                        :resize="false"
                        preview
                      />
                    </span>
                  </div>

                  <IconCropper
                    v-if="cropDialogVisible"
                    :widget-instance-id="widgetInstanceId"
                    :visible="cropDialogVisible"
                    :icon="pviewIcon"
                    :org-img-url="getCropOrgImgUrl()"
                    :cateId="curTab.key"
                    @confirm="confirmCrop"
                    @cancel="cancelCrop"
                  />

                </div>
              </div>
            </div>

            <!-- 图片预览 -->
            <div class="preview">
              <div
                v-show="!multiActsAvailable"
                :class="`icon_line for_${curTab.key}`"
              >
                <div
                  class="icon_line_inner"
                >
                  <Icon
                    v-if="isPviewShow"
                    ref="pviewIcon"
                    :conf="pviewIcon"
                    :resize="false"
                    preview
                  />
                  <Icon
                    v-if="isOrgPviewShow"
                    ref="pviewOrgIcon"
                    :conf="pviewOrgIcon"
                    class="pviewOrgIcon"
                    :resize="false"
                    preview
                  />
                  <div
                    v-show="pviewIcon.icon_id"
                    class="tool_btns"
                  >
                    <Icon
                      :conf="getToolIcon('vs_icon_dev_shanchu')"
                      :resize="false"
                      :title="$demoi18n('btn.delete')"
                      @click="delIcon"
                    />
                    <Icon
                      v-show="pviewIcon.imgStyle && pviewIcon.imgStyle.width < 300"
                      :conf="getToolIcon(isOrgPview ? 'vs_icon_dev_suoxiao1' : 'vs_icon_dev_fangda')"
                      :resize="false"
                      :title="$demoi18n('iconEditor.zoom')"
                      @click="toggleOrgPview"
                    />
                    <Icon
                      v-show="cropBtnShow"
                      :conf="getToolIcon('vs_icon_dev_caiqie')"
                      :resize="false"
                      :title="$demoi18n('iconEditor.cut')"
                      @click="openCropDialog"
                    />
                  </div>
                </div>
              </div>
              <div
                v-show="configLineShow && !multiActsAvailable"
                class="config_line"
              >
                <el-button
                  class="reset_btn"
                  :title="$demoi18n('btn.reset')"
                  size="small"
                  :link="true"
                  type="primary"
                  icon="RefreshRight"
                  @click="resetStyle"
                ></el-button>
                <PanelLabelOverflowTooltip ref="panelLabelOverflowTooltip" />
                <el-form
                  ref="pviewIconForm"
                  v-panel-label-overflow-tooltip="getPanelLabelOverflowTooltip()"
                  :model="pviewIcon"
                  label-width="80px"
                >
                  <el-tabs v-model="activeConfTab">
                    <el-tab-pane
                      :label="$demoi18n('panel.th.picture')"
                      name="imgStyle"
                    >
                      <VsFormItem
                        v-if="curTab.key === mapIconCateId"
                        :label="$demoi18n('word.color')"
                        :helptip="$demoi18n('common.icon-editor.pointIconColorTip')"
                      >
                        <ColorPicker v-model:value="pviewIcon.imgStyle.color" />
                      </VsFormItem>
                      <CssStyleEditor
                        :css-style="pviewIcon.imgStyle"
                        :df-attrs="pviewIcon.imgStyle"
                        option="imgStyle"
                        :hidden-fields="hiddenImgStyleFields"
                      />
                    </el-tab-pane>
                    <el-tab-pane
                      v-if="pviewIcon.type === 'iconfont'"
                      :label="$demoi18n('panel.th.container')"
                      name="boxStyle"
                    >
                      <CssStyleEditor
                        :css-style="pviewIcon.boxStyle"
                        :df-attrs="pviewIcon.boxStyle"
                        option="boxStyle"
                      />
                    </el-tab-pane>
                  </el-tabs>
                </el-form>
              </div>
            </div>
          </div>
        </div>
      </div>
      <template #footer>
        <span
          class="footer"
        >
          <el-button
            size="default"
            type="primary"
            @click="save"
          >{{ $demoi18n('btn.confirm') }}</el-button>
          <el-button
            size="default"
            @click="cancel"
          >{{ $demoi18n('btn.cancel') }}</el-button>
        </span>
      </template>
    </el-dialog>

    <!-- 转移分类弹窗 -->
    <el-dialog
      v-if="movePopVisible"
      v-model="movePopVisible"
      :title="$demoi18n('icon-editor.transferCate')"
      :class="`move_icon_dialog ${visualThemeClassName} ${xvueNameSpace}`"
      :close-on-click-modal="false"
      :append-to-body="true"
      :destroy-on-close="true"
      width="350px"
      @close="cancelMoveServerImgs()"
    >
      <div class="move_icon_box">
        <div class="tip">{{ $demoi18n('icon-editor.batchTransferTip') }}</div>
        <el-select v-model="targetCateId" filterable :placeholder="$demoi18n('view.select.placeholder')">
          <el-option
            v-for="item in targetTabs"
            :key="item.key"
            :label="item.name"
            :value="item.key"
          >
          </el-option>
        </el-select>
      </div>
      <template #footer>
        <span
          class="footer"
        >
          <el-button
            size="default"
            type="primary"
            @click="doMoveServerImgs()"
          >{{ $demoi18n('btn.confirm') }}</el-button>
          <el-button
            size="default"
            @click="cancelMoveServerImgs()"
          >{{ $demoi18n('btn.cancel') }}</el-button>
        </span>
      </template>
    </el-dialog>

    <div
      v-if="rightMenu.visible"
      class="right_menu"
      :style="getCssStyle(rightMenu.style, false)"
    >
      <div @click="openCropDialog()">{{ $demoi18n('iconEditor.cut') }}</div>
    </div>
  </div>
</template>

<script>
import SiteAPI from '@/apis/site.js';
import iconApi from '@/apis/iconApi.js';
import ColorPicker from '@/components/common/color-picker/color-picker.vue';
import CssStyleEditor from '@/components/common/css-style-editor/css-style-editor.vue';
import IconCropper from '@/components/common/icon/icon-cropper.vue';
import dfIcon from '@/components/common/icon/icon-default.js';
import IconUploadMixin from '@/components/common/icon/icon-upload-mixin.js';
import IconUploader from '@/components/common/icon/icon-uploader.vue';
import PanelLabelOverflowTooltip from '@/components/common/overflow-tooltip/overflow-tooltip.vue';
import VsFormItem from '@/components/common/vs-form-item/vs-form-item.vue';
import storage from '@/utils/ado-self/ado-storage';
import { $confirm, dropArrItem, getCssStyle,
  getServerImgUrl, isArray, isNum, isObject,
  getServerImgUrlByIcon, convertImgUrlToBlob } from '@/utils/util.js';
import vsIcon1 from 'public/iconfont/vs_icon1/iconfont.json';
import vsIcon2 from 'public/iconfont/vs_icon2/iconfont.json';
import vsIcon3 from 'public/iconfont/vs_icon3/iconfont.json';
import { merge as _merge } from 'lodash';
import Icon from './icon.vue';
import pngIcons from './icons/icon-map.js';
import { nextTick } from 'vue';
import IconEditorCategory from './icon-editor-category.vue';
import IconModes from '@/components/common/icon/icon-modes.js';
import presetCates from '@/components/common/icon/preset-cates.js';

const storageKey = 'visual_components_uploaded_imgs';

const iconfontIcons = {
  vsIcon1,
  vsIcon2,
  vsIcon3,
};

const dfBoxStyle = {
  backgroundColor: null,
  width: 50,
  height: 50,
  borderRadius: 0,
  borderWidth: 1,
  borderColor: null,
};

const dfImgStyle = {
  color: null,
  width: 50,
  height: 50,
  fontSize: 24,
};

const dfFontColor = {
  light: '#3c3c3c',
  dark: '#00f7ff',
};

const getIconfontList = key => {
  const list = iconfontIcons[key].glyphs.map(n => {
    n.fontClass = iconfontIcons[key].css_prefix_text + n.font_class;
    return n;
  });
  return list;
};

export default {
  components: {
    Icon,
    CssStyleEditor,
    IconUploader,
    IconCropper,
    PanelLabelOverflowTooltip,
    VsFormItem,
    ColorPicker,
    IconEditorCategory,
  },
  mixins: [IconUploadMixin],
  props: {
    widgetInstanceId: String,
    icon: {
      type: [Object, String],
      default: () => ({}),
    },

    // 选传参数
    componentStyle: {
      type: String,
      default: 'dark',
    },

    rooterWidth: {
      type: Number,
      default: 26,
    },

    // 是否有同步按钮功能
    hasSync: {
      type: Boolean,
      default: false,
    },

    mode: {
      type: String,
      default: 'all',
    },

    // 老平台图片原宽高
    width: Number,
    height: Number,

    // 默认设置
    dfStyle: {
      type: Object,
      default: null,
    },
  },
  emits: ['save', 'sync'],
  data() {
    return {
      xvueNameSpace: process.env.xvueNameSpace, // 给挂载在body下的元素加上主类名
      serverTabs: [],
      targetCateId: '',
      popoverVisible: false,
      dialogVisible: false,
      pviewIcon: {
        'icon_id': '',
        'sourceIcon_id': '',
        boxStyle: { ...dfBoxStyle },
        imgStyle: { ...dfImgStyle },
      },
      colors: ['#26B0FF', '#5B8FF9', '#21C504', '#ffffff', '#C089D9', '#F6BD16', '#FE4C56'],
      lightColors: ['#26B0FF', '#008DF0', '#00B6C7', '#21C504', '#C089D9', '#F6BD16', '#FE4C56'],
      darkColors: ['#ffffff', '#26B0FF', '#5B8FF9', '#21C504', '#C089D9', '#F6BD16', '#FE4C56'],
      bgColors: ['', '#bfbfbf', '#BAFFF6', '#E1FFDB'],

      iconsMap: {
        custom: {
          type: 'serverImg',
          list: [],
        },
        default: {
          type: 'png',
          list: pngIcons.default,
        },
        white: {
          type: 'png',
          list: pngIcons.white,
        },
        tabLine: {
          type: 'png',
          list: pngIcons.tabLine,
        },
        vsIcon1: {
          type: 'iconfont',
          list: getIconfontList('vsIcon1'),
        },
        vsIcon2: {
          type: 'iconfont',
          list: getIconfontList('vsIcon2'),
        },
        vsIcon3: {
          type: 'iconfont',
          list: getIconfontList('vsIcon3'),
        },
      },
      dfPng: {
        type: 'png',
        boxStyle: {
          ...dfBoxStyle,
        },
        imgStyle: {
          ...dfImgStyle,
        },
      },
      dfIconfont: {
        type: 'iconfont',
        boxStyle: {
          ...dfBoxStyle,
        },
        imgStyle: {
          ...dfImgStyle,
        },
      },
      dfServerImg: {
        type: 'serverImg',
        boxStyle: {
          ...dfBoxStyle,
        },
        imgStyle: {
          ...dfImgStyle,
        },
      },
      pvLoading: true,
      activeConfTab: 'imgStyle',
      cropDialogVisible: false,
      rightMenu: {
        visible: false,
        style: {
          left: 0,
          top: 0,
        },
      },
      cateIconList: [], // 分类下的图片
      isOrgPview: false,

      serverImgAllSelected: false,
      multiActsAvailable: false,
      selectedIconIds: [],
      sizeRadioLock: false, // 等比缩放锁定
      sizeChanging: false,
      curTab: {
        key: '',
      },
      movePopVisible: false,

      // 滚动加载
      scorllLock: false, // 滚动加载锁
      currentPage: 1, // 当前页
      pageSize: 70, // 每页请求图片数量
      pageLoading: false, // 分页图片加载中
      allLoaded: false, // 是否已全部图片加载完
      pageLoadTimer: null,
      mapIconCateId: presetCates['map'], // 地图图片分类id，后端固定返回
    };
  },
  computed: {
    rooterIcon() {
      let conf = this.getConf();
      const width = conf.type === 'iconfont' ? conf.boxStyle.width : conf.imgStyle.width;
      const rate = this.rooterWidth / width;
      conf = this.zoomConf(conf, rate);
      return conf;
    },
    rooterIconStyle() {
      const conf = this.getConf();
      const style = {};
      if (conf.type !== 'iconfont') {
        style.backgroundColor = '#38728e';
      }
      return style;
    },
    emptyIcon() {
      const isDark = window._adoPremise.uc.theme === 'dark';
      let conf = {
        type: 'iconfont',
        fontClass: 'vs_icon_dev_bitmap-copy',
        boxStyle: {
          color: isDark ? '#0eb4c2' : '#000',
          backgroundColor: isDark ? '#091a2d' : '#fff',
          width: 26,
          height: 26,
        },
        imgStyle: {
          color: null,
          fontSize: 12,
        },
      };
      const rate = this.rooterWidth / conf.boxStyle.width;
      conf = this.zoomConf(conf, rate);
      return conf;
    },
    hiddenImgStyleFields() {
      const { pviewIcon } = this;
      if (pviewIcon.type === 'iconfont') {
        if (this.mode === 'rank') {
          return ['width', 'height', 'color'];
        }
        return ['width', 'height'];
      } else {
        if (pviewIcon.sourceIcon_id && pviewIcon.sourceIcon_id.includes('tabLine')) {
          return ['fontSize', 'height', 'color'];
        }
        return ['fontSize', 'color'];
      }
    },
    pviewOrgIcon() {
      const conf = JSON.parse(JSON.stringify(this.pviewIcon));
      conf.imgStyle.width = 300;
      conf.imgStyle.fontSize = 100;
      conf.boxStyle.width = 300;
      conf.boxStyle.height = 300;
      delete conf.imgStyle.height;
      return conf;
    },

    cropBtnShow() {
      const { type, sourceIcon_id: sourceIconId = '' } = this.pviewIcon;
      if (type === 'serverImg' && !/default|tabLine/.test(sourceIconId)) {
        return true;
      }
      return false;
    },
    configLineShow() {
      const isShow = this.pviewIcon.icon_id && !this.isOrgPview && IconModes[this.mode].configLineShow;
      return isShow;
    },
    isPviewShow() {
      const { width } = this.pviewIcon.imgStyle;
      const isBig = width && width > 300;
      return !this.pvLoading && this.pviewIcon.icon_id && !this.isOrgPview && !isBig;
    },
    isOrgPviewShow() {
      const { width } = this.pviewIcon.imgStyle;
      const isBig = width && width > 300;
      return !this.pvLoading && this.pviewIcon.icon_id && (this.isOrgPview || isBig);
    },
    hasSelected() {
      return this.selectedIconIds.length === 0;
    },
    targetTabs() {
      return this.serverTabs.filter(n => n.key !== this.curTab.key && n.isAuto === 0);
    },
  },
  watch: {
    'rightMenu.visible'(value) {
      if (value) {
        document.body.addEventListener('click', this.closeRightMenu);
      } else {
        document.body.removeEventListener('click', this.closeRightMenu);
      }
    },
    'pviewIcon.imgStyle.width'(val, oldVal) {
      const { type } = this.pviewIcon;
      if (type === 'serverImg' || type === 'png') {
        this.pviewIcon.boxStyle.width = val;
      }
      if (this.sizeRadioLock && !this.sizeChanging) {
        this.pviewIcon.imgStyle.height = Math.round((val / oldVal) * this.pviewIcon.imgStyle.height);
        this.sizeChanging = true;
        nextTick(() => {
          this.sizeChanging = false;
        });
      }
    },
    'pviewIcon.imgStyle.height'(val, oldVal) {
      const { type } = this.pviewIcon;
      if (type === 'serverImg' || type === 'png') {
        this.pviewIcon.boxStyle.height = val;
      }
      if (this.sizeRadioLock && !this.sizeChanging) {
        this.pviewIcon.imgStyle.width = Math.round((val / oldVal) * this.pviewIcon.imgStyle.width);
        this.sizeChanging = true;
        nextTick(() => {
          this.sizeChanging = false;
        });
      }
    },
    'pviewIcon.type'(val) {
      if (val !== 'iconfont') {
        this.activeConfTab = 'imgStyle';
      }
    },
    dialogVisible(val) {
      if (val) {
        this.pvLoading = true;
        nextTick(() => {
          this.pviewIcon = this.getConf();
          if (this.pviewIcon.icon_id) {
            this.selectedIconIds = [this.pviewIcon.icon_id];
          } else {
            this.selectedIconIds = [];
          }
          this.pvLoading = false;
        });

        this.multiActsAvailable = false;
      } else {
        this.iconsMap.custom.list = []; // 请空清单，防止本地图片混用到别的组件
      }
    },
    componentStyle(newVal, oldVal) {
      const { imgStyle } = this.pviewIcon;
      if (imgStyle && newVal && oldVal) {
        imgStyle.color = dfFontColor[newVal];
      }
    },
    multiActsAvailable(val) {
      const ids = [];
      if (!val) {
        if (this.pviewIcon.icon_id) {
          ids.push(this.pviewIcon.icon_id);
        }
      }
      this.selectedIconIds = ids;
    },
  },
  methods: {
    getCssStyle,
    getPanelLabelOverflowTooltip() {
      return {
        parentComp: this,
      };
    },
    getToolIcon(fontClass) {
      const isDark = window._adoPremise.uc.theme === 'dark';
      const conf = {
        type: 'iconfont',
        fontClass,
        boxStyle: {
          color: isDark ? '#0eb4c2' : '#fff',
          backgroundColor: isDark ? '#064559' : '#e4e7ed',
          width: 26,
          height: 26,
        },
        imgStyle: {
          color: null,
          fontSize: 14,
        },
      };
      return conf;
    },
    getConf() {
      let conf = {};
      if (typeof this.icon === 'string' || !this.icon) {
        conf.type = 'serverImg';
        conf['icon_id'] = this.icon;
        conf['sourceIcon_id'] = this.icon;
        conf.apiType = 'platform';
        conf.boxStyle = { ...dfBoxStyle };
        conf.imgStyle = { ...dfImgStyle };
        if (this.width) {
          conf.imgStyle.width = this.width;
        }
        if (this.height) {
          conf.imgStyle.height = this.height;
        }
        if (this.dfStyle) {
          conf.boxStyle = { ...conf.boxStyle, ...this.dfStyle?.boxStyle || {} };
          conf.imgStyle = { ...conf.imgStyle, ...this.dfStyle?.imgStyle || {} };
        }
      } else {
        const _conf = JSON.parse(JSON.stringify(this.icon));
        conf = _merge({}, dfIcon, _conf);
      }
      return conf;
    },
    zoomConf(conf, rate) {
      const excludes = ['serType', 'isLibImg'];
      if (isObject(conf)) {
        Object.entries(conf).forEach(([i]) => {
          if (!excludes.includes(i)) {
            conf[i] = this.zoomConf(conf[i], rate);
          }
        });
      } else if (isArray(conf)) {
        for (let i = 0; i < conf.length; i++) {
          conf[i] = this.zoomConf(conf[i], rate);
        }
      } else {
        let _conf = conf;
        if (isNum(_conf)) {
          _conf = _conf * rate;
        }
        return _conf;
      }
      return conf;
    },
    async setActiveTab(tab) {
      this.currentPage = 1;
      this.pageLoading = false;
      this.allLoaded = false;
      clearTimeout(this.pageLoadTimer);
      this.cateIconList = [];
      this.scorllLock = true;

      if (tab !== this.curTab) {
        this.multiActsAvailable = false;
      }
      this.curTab = tab;
      if ((tab.type === 'serverImg' || tab.type === 'serverImgDefault') && tab.key !== 'custom') {
        await this.getCateIconList();
        this.scorllLock = false;
      }
    },
    selectIcon(img) {
      if (img.isAuto && this.multiActsAvailable) {
        return;
      }

      const iconId = img['icon_id'];
      const iconVm = this.$refs[iconId][0];

      // 多选操作模式
      if (this.multiActsAvailable) {
        if (this.selectedIconIds.includes(iconId)) {
          this.selectedIconIds = dropArrItem(this.selectedIconIds, iconId);
        } else {
          this.selectedIconIds.push(iconId);
        }
        return;
      }

      // 单选预览模式
      if (iconId === this.pviewIcon.icon_id) {
        return;
      }

      const fromIcon = this.pviewIcon;
      const toIcon = JSON.parse(JSON.stringify(iconVm.conf));

      if (fromIcon.type === toIcon.type) {
        toIcon.boxStyle = { ...fromIcon.boxStyle };
      }
      toIcon.imgStyle = { ...fromIcon.imgStyle };

      if (!fromIcon.imgStyle.color) {
        toIcon.imgStyle.color = dfFontColor[this.componentStyle];
      }
      this.selectedIconIds = [toIcon.icon_id];

      this.isOrgPview = false;
      this.pvLoading = true;
      nextTick(() => {
        this.pviewIcon = toIcon;
        this.pvLoading = false;
        this.resetSerImgSize();
      });
    },
    editIcon() {
      this.dialogVisible = true;
      this.popoverVisible = false;
    },
    delIcon() {
      this.pvLoading = true;

      // 删除选中的icon
      const index = this.selectedIconIds.findIndex(item => item === this.pviewIcon.icon_id);
      if (index >= 0) {
        this.selectedIconIds.splice(index, 1);
      }
      this.pviewIcon = JSON.parse(JSON.stringify(dfIcon));
      nextTick(() => {
        this.pvLoading = false;
      });
    },

    // 检查预览图片是否存在，不存在则重置为未选预览图片状态
    async checkPviewIcon() {
      const { icon_id: iconId, type } = this.pviewIcon;
      if (iconId && type === 'serverImg') {
        const httpUrl = getServerImgUrlByIcon(this.pviewIcon, true);
        const blob = await convertImgUrlToBlob(httpUrl);
        if (!blob) {
          this.delIcon();
        }
      }
    },
    async cancel() {
      await this.checkPviewIcon();
      if (!this.pviewIcon.icon_id) { // 删除了图片，取消时需要显示未设置图片状态
        const iconConf = JSON.parse(JSON.stringify(this.pviewIcon));
        this.$emit('save', iconConf);
      }
      this.dialogVisible = false;
    },
    async save() {
      await this.checkPviewIcon();
      const res = await this.uploadPreviewIcon();
      if (res.isSuccess) {
        const iconConf = JSON.parse(JSON.stringify(this.pviewIcon));

        this.$emit('save', iconConf);
        this.dialogVisible = false;
      }
    },
    getPngIcon(n) {
      const style = {
        ...this.dfPng,
        src: n.src,
        'icon_id': n.icon_id,
        'sourceIcon_id': n.icon_id,
      };
      return style;
    },
    getIconfontIcon(n) {
      const style = {
        ...this.dfIconfont,
        fontClass: n.fontClass,
        'icon_id': n.icon_id,
        'sourceIcon_id': n.icon_id,
      };
      return style;
    },
    getServerImgIcon(n, serType = 6, isLibImg = false) {
      return {
        ...this.dfServerImg,
        'icon_id': n.icon_id,
        apiType: 'xvue',
        'sourceIcon_id': n.icon_id,
        serType,
        isLibImg,
      };
    },
    getClassName(img) {
      const ids = [img.icon_id];
      const isOn = ids.some(n => this.selectedIconIds.includes(n));

      return {
        on: isOn,
        it: true,
        isAuto: img.isAuto && this.multiActsAvailable,
      };
    },
    initDfCssStyleAttrs() {
      return {
        boxStyle: this.pviewIcon.boxStyle,
        imgStyle: this.pviewIcon.imgStyle,
      };
    },
    hasConf() {
      if (!this.icon) {
        return false;
      }
      if (typeof this.icon === 'string') {
        return true;
      } else if (this.icon.icon_id) {
        return true;
      } else {}
      return false;
    },
    uploadComplete(result) {
      if (result.isSuccess) {
        const iconId = result.imgId;
        if (this.curTab.key === 'custom') {
          this.iconsMap.custom.list.unshift({
            'icon_id': iconId,
          });
        } else {
          this.cateIconList.unshift({
            'icon_id': iconId,
            'isAuto': false,
            'isLibImg': true,
          });
          this.$refs.cates.updateImgCounts();
        }
        nextTick(() => {
          this.selectIcon({ 'icon_id': iconId });
        });
      } else {
        if (result.action === 'crop' && result.isUseCrop === false) { // 裁切图片
          return; // 使用原图
        }
        this.$message.error(result.message);
      }
    },
    openCropDialog() {
      this.cropDialogVisible = true;
    },
    confirmCrop(res) {
      const conf = JSON.parse(JSON.stringify(this.pviewIcon));

      this.uploadComplete(res);

      this.pvLoading = true;
      this.cropDialogVisible = false;
      nextTick(() => {
        this.pviewIcon = conf;
        this.pvLoading = false;
        this.resetSerImgSize();
      });
    },
    cancelCrop() {
      this.cropDialogVisible = false;
    },
    getCropOrgImgUrl() {
      const { icon_id: iconId, apiType, isLibImg } = this.pviewIcon;
      const { serType } = this.pviewIcon;
      let url = getServerImgUrl(iconId, apiType, true);

      if (serType === 5 || serType === 9) {
        const splitor = url.includes('?') ? '&' : '?';
        url += `${splitor}type=${serType}`;
      }
      return url;
    },
    sync() {
      this.$emit('sync', this.icon);
    },
    uploadPreviewIcon() {
      return new Promise(resolve => {
        const { pviewIcon } = this;

        if (pviewIcon.type === 'png') {
          // base64图片上传
          const fileName = `${new Date().getTime()}.png`; // 随机文件名
          const blob = this.convertBase64UrlToImgFile(pviewIcon.src, fileName, 'image/png');
          this.uploadBlob(blob, 6).then(res => {
            resolve(res);
          });
        } else {
          resolve({ isSuccess: true });
        }
      });
    },
    uploadBlob(blob, type) {
      return new Promise(resolve => {
        const obj = { file: blob, type };
        this.uploadImageData(obj).then(res => {
          if (res.isSuccess) {
            const conf = JSON.parse(JSON.stringify(this.pviewIcon));
            conf.type = 'serverImg';
            conf.apiType = 'xvue';
            conf['icon_id'] = res.imgId;
            conf.src = '';
            this.pviewIcon = conf;
          } else {
            this.$message.error(res.message);
          }
          resolve(res);
        });
      });
    },
    async getCateIconList() {
      const res = await iconApi.getIconsInCate({
        cateId: this.curTab.key,
        currentPage: this.currentPage,
        pageSize: this.pageSize,
      });
      let icons = res.data.data.list;
      icons = icons.map(n => ({
        'icon_id': n.imageId,
        'isLibImg': true,
        ...n,
      }));

      this.pageLoading = false;
      if (icons.length < this.pageSize) {
        this.allLoaded = true;
      }
      this.cateIconList = this.cateIconList.concat(icons);
    },
    toggleOrgPview() {
      this.isOrgPview = !this.isOrgPview;
    },
    resetSerImgSize(maxCount = 10) {
      if (maxCount <= 0) {
        return;
      }
      const { pviewIcon } = this;
      if (pviewIcon.type === 'serverImg') {
        const imgRef = this.$refs['pviewIcon'] || this.$refs['pviewOrgIcon'];
        let imgEl = imgRef && imgRef.$el.querySelector('img');
        if (imgEl && imgEl.naturalWidth) {
          pviewIcon.imgStyle.width = imgEl.naturalWidth;
          pviewIcon.imgStyle.height = imgEl.naturalHeight;
        } else {
          setTimeout(() => this.resetSerImgSize(maxCount - 1), 200);
        }
        imgEl = null;
      }
    },
    resetStyle() {
      if (this.pviewIcon.type === 'serverImg') {
        this.resetSerImgSize();
      } else {
        this.pviewIcon.imgStyle = { ...dfIcon.imgStyle, color: dfFontColor[this.componentStyle] };
        this.pviewIcon.boxStyle = { ...dfIcon.boxStyle };
      }
    },
    async doDelServerImgs() {
      let deleteResult = true;
      if (this.curTab.key === 'custom') {
        let { list } = this.iconsMap.custom;
        list = list.filter(n => this.selectedIconIds.includes(n.icon_id) === false);
        this.iconsMap.custom.list = list;
      } else {
        const res = await iconApi.deleteCateImgs(this.selectedIconIds);
        const { successList = [], failList = [] } = res.data.data;
        if (failList.length) {
          this.$message.warning(this.$demoi18n('icon-editor.imgBeUsedCanNotDel'));
          deleteResult = false;
        } else {
          this.selectedIconIds = [];
        }

        this.cateIconList = this.cateIconList.filter(n => !successList.includes(n['icon_id']));
        this.$refs.cates.updateImgCounts();
      }

      if (deleteResult) {
        this.$message.success(this.$demoi18n('icon-editor-category.deleteSuccess'));
      }
    },
    delSeverImgs(all = false) {
      const tip = all ? this.$demoi18n('iconEditor.delSelectAllImgsTip') : this.$demoi18n('iconEditor.delSelectImgsTip');
      $confirm(tip, this.$demoi18n('popup.title.tips'), {
        confirmButtonText: this.$demoi18n('btn.confirm'),
        cancelButtonText: this.$demoi18n('btn.cancel'),
        type: 'warning',
        closeOnClickModal: false,
      }).then(() => {
        if (all) {
          this.toggleSelectAll(true);
        }
        this.doDelServerImgs();
      });
    },
    toggleSelectAll(flag) {
      if (flag === true || flag === false) {
        this.serverImgAllSelected = flag;
      }
      if (this.serverImgAllSelected) {
        if (this.curTab.key === 'custom') {
          this.selectedIconIds = this.iconsMap.custom.list.map(n => n.icon_id);
        } else {
          this.selectedIconIds = this.cateIconList.filter(n => !n.isAuto).map(n => n.icon_id);
        }
      } else {
        this.selectedIconIds = [];
      }
    },
    serverImgLoadErr(img) {
      dropArrItem(this.iconsMap.custom.list, img);
    },
    toggleActExtends(val) {
      if (val === true || val === false) {
        this.multiActsAvailable = val;
      } else {
        this.multiActsAvailable = !this.multiActsAvailable;
      }
    },

    onGetSeverCates(serverTabs) {
      this.serverTabs = serverTabs;
    },
    moveServerImgs() {
      this.targetCateId = '';
      this.movePopVisible = true;
    },
    async doMoveServerImgs() {
      if (!this.targetCateId) {
        this.$message.error(this.$demoi18n('icon-editor.plsSelectCate'));
        return;
      }

      const res = await iconApi.moveIconsToCate(this.targetCateId, this.selectedIconIds);
      const { code } = res.data;
      if (code === 200) {
        if (this.curTab.key === 'custom') { // 自定义分类暂不支持转移
          this.iconsMap.custom.list = this.iconsMap.custom.list.filter(n => !this.selectedIconIds.includes(n['icon_id']));
        } else {
          this.cateIconList = this.cateIconList.filter(n => !this.selectedIconIds.includes(n['icon_id']));
          this.$refs.cates.updateImgCounts();
        }

        this.selectedIconIds = [];
        this.movePopVisible = false;
      } else if (code === 100108) {
        this.$message.error(this.$demoi18n('icon-editor.tranImgLimitExpired'));
      } else {
        this.$message.error(this.$demoi18n('icon-editor.failedToTransferCate'));
      }
    },
    cancelMoveServerImgs() {
      this.movePopVisible = false;
    },
    scrollGetCateImgs() {
      if (this.scorllLock) {
        return;
      }
      const container = this.$refs.cateImgs;
      const { scrollHeight } = container;
      const { scrollTop } = container;
      const { clientHeight } = container;
      if (scrollHeight - scrollTop - clientHeight <= 10 && !this.pageLoading && !this.allLoaded) {
        this.currentPage++;
        this.loadPageImages();
      }
    },
    loadPageImages() {
      if (this.pageLoading || this.allLoaded) {
        return;
      }
      this.pageLoading = true;

      clearTimeout(this.pageLoadTimer);
      this.pageLoadTimer = setTimeout(() => {
        this.getCateIconList();
      }, 100);
    },
  },
};
</script>
<style lang="less" scoped>
.visualComponents_theme_light{
  --border-color: #e8e8e8;
}
.visualComponents_theme_dark{
  --border-color: #588ba8;
}

.icon-editor {
  cursor: pointer;
  display: inline-flex;
  :deep(.el-popover__reference) {
    display: flex;
  }
  .rooter_icon {
    min-height: 20px;
    max-height: 50px;
  }
  .empty_icon {
    border: 1px dashed #e0e0e0;
    &:hover {
      border: 1px dashed #2d8cf0;
    }
  }
  .right_menu {
    position: fixed;
    left: 0;
    top: 0;
    z-index: 10000;
    background-color: #fff;
    border: 1px dashed #c7c7c7;
    padding: 2px 10px;
    font-size: 12px;
    color: #666;
  }
}

// .icon_editor_dialog{
  .icons_box {
    .icon_box_tips{}
    .icon_box_conts{
      display: flex;
      border: 1px solid var(--border-color);
      height: 640px;
      width: 991px;
      margin-top: 10px;
    }
    .icons_wrap {
      display: flex;
      padding: 20px;
      margin-top: 0;
      flex: 1;
      .icons {
        height: 100%;
        flex: 1;
        .list {
          height: 100%;
          .for_serverImg_inner {
            display: flex;
            flex-direction: column;
            .topBtns {
              flex: 0;
              display: flex;
              justify-content: space-between;
              align-items: center;
              .actions {
                width: 100%;
                flex: 1;
                display: flex;
                justify-content: flex-end;
                align-items: center;
                padding-right: 10px;
                .action_btns {
                  margin-right: 40px;
                  .el-button {
                    margin-right: 10px;
                  }
                }
                .batch_rooter {
                  margin-left: 5px;
                  margin-right: 10px;
                  color: gray;
                  &.on {
                    color: #409eff;
                  }
                }
              }
            }
            .actions_extend {
              display: flex;
              align-items: center;
              justify-content: flex-end;
              margin-right: 10px;
              margin-top: 5px;
              .cancel_select_all {
                margin-left: 5px;
              }
            }
          }
          .list_inner {
            margin-top: 20px;
            flex: 1;
            display: flex;
            flex-wrap: wrap;
            overflow-y: auto;
            align-content: flex-start;
            &.tab_00000001-0000-0000-0003-000000000000{
              .it{
                background-color: #38728e;
              }
            }
            .custom_desc{
              width: 100%;
              color: #939393;
              padding-left: 5px;
            }
          }
          > div {
            height: 100%;
            .it {
              cursor: pointer;
              margin: 5px;
              display: inline-flex;
              box-sizing: border-box;
              flex-direction: column;
              justify-content: center;
              align-items: center;
              width: 52px;
              height: 52px;
              border: 1px solid transparent;
              &.on {
                background-color: #f2ffec;
                position: relative;
                opacity: 0.8;
                overflow: hidden;
                &::before{
                  content: "";
                  width: 100%;
                  height: 100%;
                  background: url(./select.png) no-repeat transparent scroll;
                  z-index: 1;
                  position: absolute;
                  background-size: 50% 50%;
                  background-position: center;
                }
                &::after{
                  content: "";
                  position: absolute;
                  background-color: #00aaff;
                  width: 100%;
                  height: 100%;
                  text-align: center;
                  vertical-align: middle;
                  line-height: 50px;
                  opacity: 0.7;
                }
              }
              &.isAuto{
                border: 1px solid #333333;
                cursor: no-drop;
                opacity: 0.2;
              }
            }
            .icon_uploader_wrap {
              border: 1px dashed #d9d9d9;
            }
          }
        }
      }
      .preview {
        width: 300px;
        flex-shrink: 0;
        margin-left: 10px;
        .icon_line {
          display: flex;
          justify-content: center;
          align-items: center;
          border: 1px solid #ddd;
          height: 300px;
          position: relative;
          overflow: hidden;
          &.for_00000001-0000-0000-0003-000000000000{
            background-color: #38728e;
          }
          .pviewOrgIcon {
          }
          .tool_btns {
            position: absolute;
            right: 4px;
            bottom: 4px;
            z-index: 1;
            display: flex;
            justify-content: flex-end;
            align-items: center;
            .vs_icon {
              margin-left: -1px;
              cursor: pointer;
              border: 1px solid #dcdfe6;
              &:hover {
                background-color: #7bc4ff !important;
              }
            }
          }
        }
        .config_line {
          margin-top: 10px;
          position: relative;
          .reset_btn {
            position: absolute;
            right: 0;
            top: 6px;
            cursor: pointer;
            z-index: 1;
          }
        }
      }
    }
  }
// }
.footer {
  display: flex;
  justify-content: center;
}

.move_icon_box{
  padding-left: 50px;
  .tip{
    margin-bottom: 20px;
  }
}

.visualComponents_theme_dark {
  .empty_icon {
    border: 1px dashed #588ba8;
    &:hover {
      border: 1px dashed #0eb4c2;
    }
  }
}
</style>
<style lang="less">
.icon_editor_pop {
  box-shadow: 1px 1px 4px;
  padding: 0px 10px;
  min-width: 20px;
}
// .icon_editor_dialog {
  // width: 1030px !important;
  .el-form-item__label {
    white-space: nowrap;
    text-overflow: ellipsis;
    overflow: hidden;
  }

  .for_dark {
    .icons_wrap {
      .preview {
        .icon_line {
          background-color: #0d263a;
        }
      }
    }
  }
// }

.visualComponents_body_theme_dark {
  // .icon_editor_dialog {
    .tabs {
      background-color: #183c5a;
      li {
        color: #ffffff;
      }
    }
    .icons_wrap {
      .icons {
        .list {
          > div {
            .it {
              color: #00bcd4;
              &.on {
                background-color: #091a2d;
                border-color: #2f4d6f;
                box-shadow: none;
                color: #8bc34a;
              }
            }
          }
        }
      }
      .preview {
        .icon_line {
          background-color: #0d263a;
          border-color: #2f4d6f;
          .tool_btns {
            .vs_icon {
              border-color: #116584;
              &:hover {
                background-color: #116584 !important;
              }
            }
          }
        }
      }
    }
  // }
}
</style>
